/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2024 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef GLOBALFRICTIONCONTACT3DSOLVERS_H
#define GLOBALFRICTIONCONTACT3DSOLVERS_H

/*!\file gfc3d_Solvers.h
  Subroutines for the resolution of contact problems with friction (3-dimensional case).

*/

#include "Friction_cst.h"
#include "GlobalFrictionContactProblem.h"
#include "SolverOptions.h"
#include "gfc3d_nonsmooth_Newton_AlartCurnier.h"

typedef void (*SolverGlobalPtr)(int, int, double*, int*, double*);
typedef void (*PostSolverGlobalPtr)(int, double*);

typedef void (*FreeSolverGlobalPtr)(GlobalFrictionContactProblem*);

/** pointer to function used to update velocity and compute error */
typedef void (*ComputeErrorGlobalPtr)(GlobalFrictionContactProblem*, double*, double*, double*,
                                      double, SolverOptions*, double, double, double*);

#if defined(__cplusplus) && !defined(BUILD_AS_CPP)
extern "C" {
#endif

void gfc3d_set_internalsolver_tolerance(GlobalFrictionContactProblem* problem,
                                        SolverOptions* options,
                                        SolverOptions* internalsolver_options, double error);

/**
   Check for trivial solution in the friction-contact 3D problem

   \param dim of the problem
   \param q global vector (n)
   \param velocity global vector (n), in-out parameter
   \param reaction global vector (n), in-out parameters
   \param globalVelocity the velocity in global coordinates
   \param options the pointer to the array of options to set
   \return int =0 if a trivial solution has been found, else = -1
*/
int gfc3d_checkTrivialCaseGlobal(int dim, double* q, double* velocity, double* reaction,
                                 double* globalVelocity, SolverOptions* options);

/**
    Non-Smooth Gauss Seidel solver with reformulation for friction-contact 3D problem

    \param problem the friction-contact 3D problem to solve
    \param velocity global vector (n), in-out parameter
    \param reaction global vector (n), in-out parameters
    \param globalVelocity global vector (m), in-out parameters
    \param info return 0 if the solution is found
    \param options the solver options :
    iparam[0] : Maximum iteration number
    iparam[4] : localsolver choice
    - 0: projection on Cone,
    - 1: Newton/AlartCurnier,
    - 2: projection on Cone with local iteration,
    dparam[0] : tolerance
    dparam[2] : localtolerance
    dparam[1] : (out) error
  */
void gfc3d_nsgs_wr(GlobalFrictionContactProblem* problem, double* reaction, double* velocity,
                   double* globalVelocity, int* info, SolverOptions* options);

void gfc3d_admm_wr(GlobalFrictionContactProblem* problem, double* reaction, double* velocity,
                   double* globalVelocity, int* info, SolverOptions* options);

void gfc3d_nonsmooth_Newton_AlartCurnier_wr(GlobalFrictionContactProblem* problem,
                                            double* reaction, double* velocity,
                                            double* globalVelocity, int* info,
                                            SolverOptions* options);

/**
    Proximal point solver with reformulation for friction-contact 3D problem

    \param problem the friction-contact 3D problem to solve
    \param velocity global vector (n), in-out parameter
    \param reaction global vector (n), in-out parameters
    \param globalVelocity global vector (m), in-out parameters
    \param info return 0 if the solution is found
    \param options the solver options :
    iparam[0] : Maximum iteration number
    iparam[4] : localsolver choice 0: projection on Cone, 1: Newton/AlartCurnier,  2:
   projection on Cone with local iteration, 2: projection on Disk  with diagonalization,
    dparam[0] : tolerance
    dparam[2] : localtolerance
    dparam[1] : (out) error
*/
void gfc3d_proximal_wr(GlobalFrictionContactProblem* problem, double* reaction,
                       double* velocity, double* globalVelocity, int* info,
                       SolverOptions* options);

/**
   Fixed Point iteration on De Saxe formulation solver with reformulation for friction-contact
   3D problem

   \param problem the friction-contact 3D problem to solve
   \param velocity global vector (n), in-out parameter
   \param reaction global vector (n), in-out parameters
   \param globalVelocity global vector (m), in-out parameters
   \param info return 0 if the solution is found
   \param options the solver options :
   iparam[0] : Maximum iteration number
   dparam[0] : tolerance
   dparam[2] : localtolerance
   dparam[1] : (out) error
*/
void gfc3d_DeSaxceFixedPoint_wr(GlobalFrictionContactProblem* problem, double* reaction,
                                double* velocity, double* globalVelocity, int* info,
                                SolverOptions* options);

/**
   Fixed Point iteration on Tresca Friction Cylinder with reformulation for friction-contact 3D
   problem

   \param problem the friction-contact 3D problem to solve
   \param velocity global vector (n), in-out parameter
   \param reaction global vector (n), in-out parameters
   \param globalVelocity global vector (m), in-out parameters
   \param info return 0 if the solution is found
   \param options the solver options :
   iparam[0] : Maximum iteration number
   dparam[0] : tolerance
   dparam[2] : localtolerance
   dparam[1] : (out) error
*/
void gfc3d_TrescaFixedPoint_wr(GlobalFrictionContactProblem* problem, double* reaction,
                               double* velocity, double* globalVelocity, int* info,
                               SolverOptions* options);

/**
   Non-Smooth Gauss Seidel solver  for friction-contact 3D problem with iteration on velocities

   \param problem the friction-contact 3D problem to solve
   \param velocity global vector (n), in-out parameter
   \param reaction global vector (n), in-out parameters
   \param globalVelocity global vector (m), in-out parameters
   \param info return 0 if the solution is found
   \param options the solver options :
   iparam[0] : Maximum iteration number
   dparam[0] : tolerance
   dparam[2] : localtolerance
   dparam[1] : (out) error
*/
void gfc3d_nsgs_velocity_wr(GlobalFrictionContactProblem* problem, double* reaction,
                            double* velocity, double* globalVelocity, int* info,
                            SolverOptions* options);

/**
   Non-Smooth Gauss Seidel solver  for friction-contact 3D problem

   \param problem the friction-contact 3D problem to solve
   \param velocity global vector (n), in-out parameter
   \param reaction global vector (n), in-out parameters
   \param globalVelocity global vector (m), in-out parameters
   \param info return 0 if the solution is found
   \param options the solver options :
   iparam[0] : Maximum iteration number
   iparam[4] ; local strategy
   dparam[0] : tolerance
   dparam[2] : localtolerance
   dparam[1] : (out) error
   \todo Implement ProdTransSBM
   \todo Improve the splitting Algorithm with a smaller granularity
   \todo Use a global projection perhaps
*/
void gfc3d_nsgs(GlobalFrictionContactProblem* problem, double* reaction, double* velocity,
                double* globalVelocity, int* info, SolverOptions* options);

/**
    Solver based on the fixed-point iteration proposed by Cadoux for friction-contact 3D
   problem

    \param problem the friction-contact 3D problem to solve
    \param velocity global vector (n), in-out parameter
    \param reaction global vector (n), in-out parameters
    \param globalVelocity global vector (m), in-out parameters
    \param info return 0 if the solution is found
    \param options the solver options :
    iparam[0] : Maximum iteration number
    iparam[4] ; local strategy
    dparam[0] : tolerance
    dparam[2] : localtolerance
    dparam[1] : (out) error
*/
void gfc3d_ACLMFixedPoint(GlobalFrictionContactProblem* problem, double* reaction,
                          double* velocity, double* globalVelocity, int* info,
                          SolverOptions* options);

/**
   solver using PATH (via GAMS) for friction-contact 3D problem based on an AVI reformulation

   \param problem the friction-contact 3D problem to solve
   \param velocity global vector (n), in-out parameter
   \param reaction global vector (n), in-out parameters
   \param info return 0 if the solution is found
   \param options the solver options
*/
void gfc3d_AVI_gams_path(GlobalFrictionContactProblem* problem, double* reaction,
                         double* velocity, int* info, SolverOptions* options);

/**
   solver using PATHVI (via GAMS) for friction-contact 3D problem based on an AVI reformulation

   \param problem the friction-contact 3D problem to solve
   \param velocity global vector (n), in-out parameter
   \param reaction global vector (n), in-out parameters
   \param info return 0 if the solution is found
   \param options the solver options
*/
void gfc3d_AVI_gams_pathvi(GlobalFrictionContactProblem* problem, double* reaction,
                           double* velocity, int* info, SolverOptions* options);

void gfc3d_nonsmooth_Newton_AlartCurnier(GlobalFrictionContactProblem* problem,
                                         double* reaction, double* velocity,
                                         double* globalVelocity, int* info,
                                         SolverOptions* options);

void gfc3d_VI_ExtraGradient(GlobalFrictionContactProblem* problem, double* reaction,
                            double* velocity, double* globalVelocity, int* info,
                            SolverOptions* options);

void gfc3d_VI_FixedPointProjection(GlobalFrictionContactProblem* problem, double* reaction,
                                   double* velocity, double* globalVelocity, int* info,
                                   SolverOptions* options);

void gfc3d_ADMM(GlobalFrictionContactProblem* problem, double* reaction, double* velocity,
                double* globalVelocity, int* info, SolverOptions* options);

void gfc3d_ADMM_init(GlobalFrictionContactProblem* problem, SolverOptions* options);

void gfc3d_ADMM_free(GlobalFrictionContactProblem* problem, SolverOptions* options);

/** solver based on Interior Point Method (IPM) for friction-contact 3D problem based on an AVI
 * reformulation Vincent Acary, Paul Armand, Hoang Minh NGUYEN. High-accuracy computation of
 * rolling friction contact problems. 2022. https://hal.inria.fr/hal-03741048
 */
void gfc3d_IPM(GlobalFrictionContactProblem* problem, double* reaction, double* velocity,
               double* globalVelocity, int* info, SolverOptions* options);

void gfc3d_IPM_init(GlobalFrictionContactProblem* problem, SolverOptions* options);

void gfc3d_IPM_free(GlobalFrictionContactProblem* problem, SolverOptions* options);

void gfc3d_ipm_set_default(SolverOptions* options);

/** \addtogroup SetSolverOptions
 * @{
 */
void gfc3d_nsn_ac_set_default(SolverOptions* options);
void gfc3d_aclmfp_set_default(SolverOptions* options);
void gfc3d_admm_set_default(SolverOptions* options);

/** @} */

#if defined(__cplusplus) && !defined(BUILD_AS_CPP)
}
#endif

#endif
